#ifndef PW_PBL_COROUTINE_CHANNEL_HPP
#define PW_PBL_COROUTINE_CHANNEL_HPP

#include <functional>
#include <memory>
#include <optional>
#include <tuple>
#include <utility>
#include "Awaitor.hpp"
#include "../defer.hpp"
#include "../RingBuffer.hpp"
#include "../RustMimic.hpp"
#include "Core.hpp"

namespace pw_pbl::co::_channel
{
	template <typename T, typename RESULT>
	concept ccAwaitTo = requires(_co::TinyTransform<T> &ator) { { ator.await_resume() } -> std::same_as<RESULT>; };

	template <typename T, typename RECV, typename SEND>
	concept ccAsyncGuard = requires(T &guard) { {guard.data()}->std::same_as<Option<RECV&>>; guard.unlocker().unlock(std::declval<std::conditional_t<std::is_void_v<SEND>, std::tuple<>, SEND>>()); };

	template <typename T, typename RECV, typename SEND>
	concept ccAwaitToGuard = requires(_co::TinyTransform<T> &ator) { { ator.await_resume() } -> ccAsyncGuard<RECV,SEND>; };

	template <typename T>
	struct ForceValue
	{
		using store_type = T;
		using parm_type = T;
		static constexpr store_type &&forward(parm_type &p) { return std::forward<T>(p); }
		static constexpr parm_type &get(store_type &p) { return p; }
		static constexpr parm_type &&get(store_type &&p) { return std::forward<T>(p); }
	};
	template <>
	struct ForceValue<void>
	{
		using store_type = std::tuple<>;
		using parm_type = std::tuple<>;
		template <typename... P>
		static constexpr store_type forward(P &&...) { return {}; }
		static constexpr parm_type get(store_type) { return {}; }
	};
	template <typename T>
	struct ForceValue<T &>
	{
		using store_type = std::reference_wrapper<T>;
		using parm_type = T &;
		static constexpr store_type forward(parm_type p) { return {p}; }
		static constexpr parm_type get(store_type &p) { return p.get(); }
	};
} // namespace pw_pbl::co::_channel

namespace pw_pbl::co::channel
{

	template <typename T, typename DATA>
	concept ccAsyncRecv = requires(T &recver) { { recver.recv() } -> _channel::ccAwaitTo<DATA>; };

	template <typename T, typename DATA>
	concept ccAsyncSend = requires(T &sender) { { sender.send(std::declval<DATA>()) } -> _co::ccTransformable; };

	template <typename T, typename RECV, typename SEND>
	concept ccAsyncRecvSend = requires(T &recver) { { recver.recv() } -> _channel::ccAwaitToGuard<RECV,SEND>; };

	template <typename T, typename SEND, typename RECV>
	concept ccAsyncSendRecv = requires(T &sender) { { sender.send_recv(std::declval<SEND>()) } -> _channel::ccAwaitTo<std::optional<std::conditional_t<std::is_void_v<RECV>, std::tuple<>, RECV>>>; };

	/// 单发单收信道
	/// @tparam DATA 传输的数据类型
	/// @tparam BUFCNT 缓冲单元个数，为0表示无缓冲
	template <typename DATA, size_t BUFCNT = 0>
	class SPSC
	{
		static_assert(BUFCNT != 0);
		buffer::RingBuffer<DATA, BUFCNT> data;
		SPSC(const SPSC &) = delete;
		SPSC(SPSC &&) = delete;

	public:
		constexpr SPSC() = default;
		class Sender;
		class Recver;

		constexpr Sender sender() { return {*this}; }
		constexpr Recver recver() { return {*this}; }
	};

	/// 单发单收信道发送端
	template <typename DATA, size_t BUFCNT>
	class SPSC<DATA, BUFCNT>::Sender
	{
		SPSC &channel;
		constexpr Sender(SPSC &chl) : channel(chl) {}
		Sender(const Sender &) = delete;
		friend SPSC;

	public:
		Sender(Sender &&) = default;
		auto send(DATA data)
		{
			return [&channel = channel, data = std::forward<DATA>(data)]() mutable {
				auto writable = !channel.data.is_full();
				if (writable)
					channel.data.push(std::forward<DATA>(data));
				return writable;
			};
		}
	};

	/// 单发单收信道接收端
	template <typename DATA, size_t BUFCNT>
	class SPSC<DATA, BUFCNT>::Recver
	{
		SPSC &channel;
		constexpr Recver(SPSC &chl) : channel(chl) {}
		Recver(const Recver &) = delete;
		friend SPSC;

	public:
		Recver(Recver &&) = default;
		class Awaitor
		{
			SPSC &channel;
			constexpr Awaitor(SPSC &chl) : channel(chl) {}
			Awaitor(const Awaitor &) = delete;
			friend Recver;

		public:
			Awaitor(Awaitor &&) = default;
			bool await_ready() { return !channel.data.is_empty(); }
			DATA await_resume() { return channel.data.unchecked_shift(); }
		};
		Awaitor recv() { return {channel}; }
	};

	/// 单发单收信道无缓冲特化
	template <typename DATA> requires(!std::is_reference_v<DATA>)
	class SPSC<DATA, 0>
	{
		std::optional<DATA> data;
		SPSC(const SPSC &) = delete;
		SPSC(SPSC &&) = delete;

	public:
		constexpr SPSC() = default;
		class Sender;
		class Recver;

		constexpr Sender sender() { return {*this}; }
		constexpr Recver recver() { return {*this}; }
	};

	/// 单发单收信道无缓冲特化发送端
	template <typename DATA> requires(!std::is_reference_v<DATA>)
	class SPSC<DATA, 0>::Sender
	{
		SPSC &channel;
		constexpr Sender(SPSC &chl) : channel(chl) {}
		Sender(const Sender &) = delete;
		friend SPSC;

	public:
		Sender(Sender &&) = default;
		auto send(DATA data)
		{
			return [&channel = this->channel, data = std::forward<DATA>(data)]() {
				if (channel.data.has_value)
					return false;
				channel.data.emplace(data);
				return true;
			};
		}
	};

	/// 单发单收信道无缓冲特化接收端
	template <typename DATA> requires(!std::is_reference_v<DATA>)
	class SPSC<DATA, 0>::Recver
	{
		SPSC &channel;
		constexpr Recver(SPSC &chl) : channel(chl) {}
		Recver(const Recver &) = delete;
		friend SPSC;

	public:
		Recver(Recver &&) = default;
		class Awaitor
		{
			SPSC &channel;
			constexpr Awaitor(SPSC &chl) : channel(chl) {}
			Awaitor(const Awaitor &) = delete;
			friend Recver;

		public:
			Awaitor(Awaitor &&) = default;
			bool await_ready() { return channel.data.has_value(); }
			DATA await_resume() { return *channel.data; }
		};
		Awaitor recv() { return {channel}; }
	};

	template <typename...>
	class Guard;

	/// 单发单收发收信道，发送后可等待回送结果，通常用于SEND具有引用性质需要保证引用有效的情况
	/// @tparam SEND 发送的数据类型
	/// @tparam RECV 接收的数据类型
	/// @note 通常当接收端不显示回复且放弃时，发送端会收到接收失败信息，但当RECV为void时接收端可以不显式回复，放弃时发送端仍接收正常
	template <typename SEND, typename RECV>
	class SPSCsr
	{
		using TSendF = _channel::ForceValue<SEND>;
		using TRecv = std::conditional_t<std::is_void_v<RECV>, std::tuple<>, RECV>;
		enum class ID : uint8_t
		{
			None = 0,
			Sended = 1,			// 发送端已发送数据
			DiscardResult = 2,	// 接收端已接收，但在回送结果前发送已放弃（提前析构）
			WaittingResult = 3, // 接收端已接收，正在准备回送结果
			Recved = 4,			// 接收端已回送结果
			RecvFailed = 5,		// 接收端已接收，但放弃回送结果（提前析构）
		} id;
		union TData
		{
			std::tuple<> none;
			MaybeUninit<typename TSendF::store_type> send;
			MaybeUninit<TRecv> recv;
			constexpr ~TData() {}
		} data;

	public:
		constexpr SPSCsr() : id(ID::None), data{.none{}} {};
		SPSCsr(const SPSCsr &) = delete;
		SPSCsr(SPSCsr &&) = delete;
		constexpr ~SPSCsr()
		{
			switch (id)
			{
			case ID::Sended:
				data.send.destruct();
				break;
			case ID::Recved:
				data.recv.destruct();
				break;
			default:
				break;
			}
		}

	public:
		class Sender;
		class Recver;
		using Guard = Guard<SPSCsr>;
		friend Guard;

		constexpr Sender sender() { return {*this}; }
		constexpr Recver recver() { return {*this}; }
	};

	template <typename SEND, typename RECV>
	class SPSCsr<SEND, RECV>::Sender
	{
		SPSCsr &channel;
		constexpr Sender(SPSCsr &chl) : channel(chl) {}
		Sender(const Sender &) = delete;
		friend SPSCsr;

	public:
		Sender(Sender &&) = default;
		class Awaitor
		{
			SPSCsr *channel; // 在ManualAwaitor中为空表示操作已经完成，否则实际不为空
			pw_pbl::Option<typename TSendF::store_type> data;
			constexpr Awaitor(SPSCsr &chl, typename TSendF::parm_type da) : channel(&chl), data(TSendF::forward(da)) {}
			friend Sender;

		protected:
			constexpr Awaitor() = default;

		public:
			constexpr Awaitor(Awaitor &&oth) : channel(std::exchange(oth.channel, nullptr)), data{std::move(oth.data)} {}
			constexpr bool done() const { return channel == nullptr; }
			constexpr bool await_ready()
			{
				if (data.is_some())
				{
					if (channel->id == ID::None)
					{
						channel->id = ID::Sended;
						channel->data.send.construct(std::move(data.get_unchecked()));
						data.reset();
					}
					return false;
				}
				else
					return channel->id == ID::Recved || channel->id == ID::RecvFailed;
			}
			constexpr std::optional<TRecv> await_resume()
			{
				defer dnn{[&channel = channel] { channel = nullptr; }};
				if (std::exchange(channel->id, ID::None) == ID::Recved)
				{
					defer des{[channel = channel]() { channel->data.recv.destruct(); }};
					return {std::move(channel->data.recv).get()};
				}
				else // ID::RecvFailed
					return {};
			}
			constexpr ~Awaitor()
			{
				if (channel == nullptr || data.is_some())
					return;
				switch (channel->id)
				{
				case ID::Sended:
					channel->data.send.destruct();
					channel->id = ID::None;
					break;
				case ID::WaittingResult:
					channel->id = ID::DiscardResult;
					break;
				case ID::Recved:
					channel->data.recv.destruct();
					[[fallthrough]];
				case ID::RecvFailed:
					channel->id = ID::None;
					break;
				default:
					break;
				}
			}
		};
		constexpr Awaitor send_recv(typename TSendF::parm_type data) { return {channel, TSendF::forward(data)}; }

		struct ManualAwaitor : public Awaitor
		{
			using Awaitor::Awaitor;
			constexpr ManualAwaitor(Awaitor &&ator) : Awaitor(std::move(ator)) {}
			constexpr void operator=(Awaitor &&ator) { std::destroy_at(this), std::construct_at(this, std::move(ator)); }
		};
	};

	template <typename SEND, typename RECV>
	class SPSCsr<SEND, RECV>::Recver
	{
		SPSCsr &channel;
		constexpr Recver(SPSCsr &chl) : channel(chl) {}
		Recver(const Recver &) = delete;
		friend SPSCsr;

	public:
		class Unlocker;
		Recver(Recver &&) = default;
		class Awaitor
		{
			SPSCsr &channel;
			constexpr Awaitor(SPSCsr &chl) : channel(chl) {}
			friend Recver;

		public:
			constexpr bool await_ready() { return channel.id == ID::Sended; }
			constexpr Guard await_resume()
			{
				channel.id = ID::WaittingResult;
				defer des{[&channel = channel]() { channel.data.send.destruct(); }};
				return Guard{Unlocker(channel), std::move(channel.data.send).get()};
			}
		};
		constexpr Awaitor recv() { return {channel}; }
	};

	template <typename SEND, typename RECV>
	class SPSCsr<SEND, RECV>::Recver::Unlocker
	{
		SPSCsr *channel;

		constexpr Unlocker(SPSCsr &chl) : channel(&chl) {}
		friend Recver::Awaitor;

	public:
		constexpr Unlocker() : channel(nullptr) {}
		constexpr Unlocker(Unlocker &&oth) : channel(std::exchange(oth.channel, nullptr)) {}
		constexpr void operator=(Unlocker &&oth) { std::swap(channel, oth.channel); }
		constexpr bool is_unlocked() const { return channel == nullptr; }
		constexpr void unlock(TRecv result)
		{
			if (channel == nullptr)
				return;
			if (channel->id == ID::WaittingResult)
			{
				channel->id = ID::Recved;
				if constexpr (!std::is_void_v<RECV>)
					channel->data.recv.construct(std::forward<TRecv>(result));
			}
			else if (channel->id == ID::DiscardResult)
				channel->id = ID::None;
			channel = nullptr;
		}
		constexpr void unlock() requires std::is_void_v<RECV> { unlock({}); }
		constexpr ~Unlocker()
		{
			if (channel == nullptr)
				return;
			if (channel->id == ID::WaittingResult)
			{
				if constexpr (std::is_void_v<RECV>)
					channel->id = ID::Recved;
				else
					channel->id = ID::RecvFailed;
			}
			else if (channel->id == ID::DiscardResult)
				channel->id = ID::None;
		}
	};

	template <typename SEND, typename RECV>
	class Guard<SPSCsr<SEND, RECV>>
	{
		using TChannel = SPSCsr<SEND, RECV>;
		using TSendF = _channel::ForceValue<SEND>;
		using TUnlocker = typename TChannel::Recver::Unlocker;

		TUnlocker _unlocker;
		MaybeUninit<typename TSendF::store_type> _data;

		constexpr Guard(TUnlocker unlocker, typename TSendF::parm_type data) : _unlocker(std::move(unlocker)), _data(TSendF::forward(data)) {}
		friend TChannel::Recver::Awaitor;

	public:
		constexpr Guard() = default;
		constexpr Guard(Guard &&oth) : _unlocker(std::move(oth._unlocker))
		{
			if (!_unlocker.is_unlocked())
				_data.construct(std::move(oth._data.get())), oth._data.destruct();
		}
		constexpr void operator=(Guard &&oth) { std::destroy_at(this), std::construct_at(this, std::move(oth)); }
		constexpr auto &unlocker() { return _unlocker; }
		constexpr bool is_unlocked() const { return _unlocker.is_unlocked(); }
		constexpr TUnlocker detach()
		{
			if (_unlocker.is_unlocked())
				return {};
			else
				return _data.destruct(), std::move(_unlocker);
		}
		constexpr auto &&data_unchecked() { return TSendF::get(_data.get()); }
		constexpr pw_pbl::Option<typename TSendF::parm_type &> data() { return _unlocker.is_unlocked() ? pw_pbl::Option<typename TSendF::parm_type &>{} : pw_pbl::Option<typename TSendF::parm_type &>(TSendF::get(_data.get())); }
		constexpr ~Guard()
		{
			if (!_unlocker.is_unlocked())
				_data.destruct();
		}
	};

	/// 可覆盖多发单收信道
	/// @tparam DATA 传输的数据类型
	/// @note 发送总是同步完成(如果有未被接收的数据则直接覆盖)且返回数据处理完成等待器，如无须等待数据处理完成可直接丢弃
	/// @note 接收端不直接返回数据而是返回执行器，执行器执行时会接收数据并执行动作且在数据覆盖时重启动作，直到无新数据且动作完成时退出
	template <typename DATA>
	class OverridableMPSC
	{
		enum : uint8_t
		{
			EIdle,
			EBusy,
			EPending,
		} state;
		MaybeUninit<DATA> data;

	public:
		constexpr OverridableMPSC() noexcept : state(EIdle), data() {}
		OverridableMPSC(const OverridableMPSC &) = delete;
		OverridableMPSC(OverridableMPSC &&) = delete;
		constexpr ~OverridableMPSC()
		{
			if (state == EPending)
				data.destruct();
		}

		class Sender;
		class Recver;

		constexpr Sender sender() { return {*this}; }
		constexpr Recver recver() { return {*this}; }
	};

	template <typename DATA>
	class OverridableMPSC<DATA>::Sender
	{
		OverridableMPSC &channel;

		constexpr Sender(OverridableMPSC &ch) : channel(ch) {}
		friend OverridableMPSC;

	public:
		class Awaitor
		{
			OverridableMPSC &channel;
			constexpr Awaitor(OverridableMPSC &ch) : channel(ch) {}
			friend Sender;

		public:
			constexpr bool await_ready() { return channel.state == channel.EIdle; }
			constexpr std::tuple<> await_resume() { return {}; }
		};
		constexpr Awaitor send(DATA &&data)
		{
			if (channel.state == channel.EPending)
				channel.data.destruct();
			channel.data.construct(std::move(data));
			channel.state = channel.EPending;
			return {channel};
		}
	};

	template <typename DATA>
	class OverridableMPSC<DATA>::Recver
	{
		OverridableMPSC &channel;

		constexpr Recver(OverridableMPSC &ch) : channel(ch) {}
		friend OverridableMPSC;

	public:
		class Executor;
		class [[nodiscard]] Awaitor
		{
			OverridableMPSC &channel;
			constexpr Awaitor(OverridableMPSC &ch) : channel(ch) {}
			friend Recver;

		public:
			constexpr bool await_ready() { return channel.state == channel.EPending; }
			constexpr Executor await_resume() { return {channel}; }
		};
		constexpr Awaitor recv() { return {channel}; }

		class [[nodiscard]] Executor
		{
			OverridableMPSC &channel;
			constexpr Executor(OverridableMPSC &ch) : channel(ch) {}
			friend Awaitor;

		public:
			template <typename F> requires _co::ccTransformable<std::invoke_result_t<F, DATA>>
			Task<void> execute(this Executor self, F gen_action)
			{
				defer release_channel([&self] { if (self.channel.state==self.channel.EBusy) self.channel.state = self.channel.EIdle; });
				while (self.channel.state == self.channel.EPending)
				{
					DATA data{self.channel.data.take()};
					self.channel.state = self.channel.EBusy;
					co_await Any{[&self] { return self.channel.state == self.channel.EPending; }, gen_action(std::move(data))};
				}
			}
			constexpr DATA done(this Executor self)
			{
				self.channel.state = self.channel.EIdle;
				return self.channel.data.take();
			}
		};
	};
} // namespace pw_pbl::co::channel

namespace pw_pbl
{
	template <typename SEND, typename RECV>
	class Option<co::channel::Guard<co::channel::SPSCsr<SEND, RECV>>> : public Option<std::type_identity<co::channel::Guard<co::channel::SPSCsr<SEND, RECV>>>>
	{
		using TGuard = co::channel::Guard<co::channel::SPSCsr<SEND, RECV>>;
		TGuard raw;

	public:
		constexpr Option() = default;
		constexpr Option(TGuard &&data) : raw(std::move(data)) {}
		constexpr bool is_none() const { return raw.is_unlocked(); }
		constexpr auto &&get_unchecked() { return raw; }
		constexpr auto &&get_unchecked() const { return raw; }
	};
} // namespace pw_pbl

#endif // PW_PBL_COROUTINE_CHANNEL_HPP
